/*
 * Copyright (c) 2008, Yifu Huang
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of SleekIce nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.sleekice.util;

/* the dynamic linked list */
public class List<E> {

    /* the first node of the list */
    protected ListNode<E> first;
    /* the last node of the list */
    protected ListNode<E> last;

    /* default constructor */
    public List() {
        first = null;
        last = null;
    }

    /* create a new list with an initial node */
    public List(E newObject) {
        ListNode<E> node =
            new ListNode<E>(newObject, null, null);
        first = node;
        last = node;
    }

    /* adds another node with the new object to the end of the list */
    public void add(E newObject) {
        /* this will be the initial node */
        if (first == null) {
            ListNode<E> node =
                new ListNode<E>(newObject, null, null);
            first = node;
            last = node;
        }
        else {
            ListNode<E> node =
                new ListNode<E>(newObject, null, last);
            /* link the last node in this list with the new node */
            last.setNext(node);
            /* now give alias of new node to the last node */
            last = node;
        }
    }

    /* adds another node with the new object to the front of the list */
    public void addToFront(E newObject) {
        /* this will be the initial node */
        if (first == null) {
            ListNode<E> node =
                new ListNode<E>(newObject, null, null);
            first = node;
            last = node;
        }
        else {
            ListNode<E> node =
                new ListNode<E>(newObject, first, null);
            /* link the first node in this list with the new node */
            first.setPrevious(node);
            /* now give alias of new node to the first node */
            first = node;
        }
    }

    /* deletes an object from this list */
    public void delete(E object) {
        for (ListNode<E> node = first; node != null;
            node = node.next()) {
            if (object.equals(node.getValue())) {
                delete(node);
            }
        }
    }
    
    /**
     * Deletes the first node in this list.
     */
    public void deleteFirst() {
        delete(first);
    }
    
    /**
     * Deletes the last node in this list.
     */ 
    public void deleteLast() {
        delete(last); 
    }

    /* deletes a list node */
    public void delete(ListNode<E> node) {
        ListNode<E> next = node.next();
        ListNode<E> previous = node.previous();
        /* this is the only node in the list */
        if (previous == null && next == null) {
            first = null;
            last = null;
        }
        else if (previous == null && next != null) {
            next.setPrevious(null);
            first = next;
        }
        else if (previous != null && next == null) {
            previous.setNext(null);
            last = previous;
        }
        else {
            previous.setNext(next);
            next.setPrevious(previous);
        }
    }

    /* deletes all nodes */
    public void deleteAll() {
        first = null;
        last = null;
    }

    /* get the initial node of the list */
    public ListNode<E> getFirst() {
        return first;
    }
    
    public ListNode<E> getNode(int i) {
        int count = -1;
        ListNode<E> node = first;
        while (node != null) {
            count++;
            if (count == i) {
                return node;
            }
            node = node.next();
        }
        return null;
    }

    /* get the last node of the list */
    public ListNode<E> getLast() {
        return last;
    }

    /* returns the total number of nodes in this list */
    public int getTotal() {
        int count = 0;
        ListNode current = first;
        while (current != null) {
            count++;
            current = current.next();
        }
        return count;
    }
}